package net.chowda.castcluster.provider;

import com.sun.syndication.feed.module.itunes.EntryInformationImpl;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEnclosure;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.fetcher.FeedFetcher;
import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher;
import com.sun.syndication.io.SyndFeedOutput;
import net.chowda.castcluster.CastVideoItem;
import net.chowda.castcluster.Video;
import net.chowda.castcluster.VideoProvider;
import net.chowda.castcluster.VideoSource;
import net.chowda.castcluster.util.CastClusterConfig;
import net.chowda.castcluster.util.LogUtil;
import org.apache.log4j.Logger;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * this should handle any feed format that the included version of ROME can handle...
 *
 *
 * url format:
 *              ext|url|http://www.mobuzztv.com/uk/rss/quicktime
 *
 * just ignoring the |url bit for now... in the future I think I want to add another section...
 *      perhaps a date, or date range, or a keyword filter... 
 *
 *
 */
public class WebFeedProvider extends VideoProvider {
    private static final Logger LOG = LogUtil.getLogger(WebFeedProvider.class);

    // this is a global static for now... should be fine for single user environments.
    // TODO - probably not fine.
    protected static FeedFetcherCache feedInfoCache;
    public WebFeedProvider() {
        synchronized (LOG) {
            if(feedInfoCache == null) {
                feedInfoCache = new DiskFeedInfoCache(CastClusterConfig.getInstance().getGlobalProp(CastClusterConfig.CONFIG_BASE_DIR) + File.separator + "cache");
            }
        }
    }

    public List<VideoSource> getProviderSourcesForWebUrl(String url) {
        return new ArrayList<VideoSource>();
    }

    public VideoSource getProviderSourceForCCUrl(String url) {
        VideoSource source = new VideoSource();
        source.setCcUrl(url);
        source.setUrl(url.split("\\|")[2]);
        SyndFeed syndFeed = fetchFeed(source.getUrl());
        source.setName(syndFeed.getTitle());
        source.setVideos(getProviderVideos(url));
        return source;
    }

    /**
     * we could just make this a pass through... but we don't want to have to worry about gzipped feeds down stream, and we
     * can use the disk cache mechanism to speed things along.
     */
    public String getProviderFeed(String url) {
        String rssUrl = url.split("\\|")[2];
        try {
            SyndFeed syndFeed = fetchFeed(rssUrl);
            return new SyndFeedOutput().outputString(syndFeed);
        } catch (Exception e) {
            throw new RuntimeException("problem with feed: " + rssUrl, e);
        }
    }

    public List<Video> getProviderVideos(String url) {
        String rssUrl = url.split("\\|")[2];
        return getVideosFromRss(rssUrl);
    }

    protected List<Video> getVideosFromRss(String rssUrl) {
        List<Video> videos = new ArrayList<Video>();

        // turn these feed items into our generic video items for sorting and later reconsitution.
        SyndFeed syndFeed = fetchFeed(rssUrl);
        for (Object entry : syndFeed.getEntries()) {
            SyndEntryImpl syndEntry = (SyndEntryImpl) entry;
            List list = syndEntry.getEnclosures();
            for (Object o : list) {
                CastVideoItem item = new CastVideoItem();

                SyndEnclosure enc = (SyndEnclosure) o;
                item.setLengthInSeconds((int) enc.getLength());
                item.setUrl(enc.getUrl());
                item.setVidSize(enc.getLength());

                item.setAuthor(syndEntry.getAuthor());
                SyndContent description = syndEntry.getDescription();
                if (description != null && description.getValue() != null && description.getValue().length() > 0) {
                    item.setDescription(description.getValue());
                } else {
                    // attempt to get itune desc
                    EntryInformationImpl ituneModule = (EntryInformationImpl) syndEntry.getModule("http://www.itunes.com/dtds/podcast-1.0.dtd");
                    if (ituneModule != null) {
                        item.setDescription(ituneModule.getSummary());
                        if(item.getDescription() == null) {
                            item.setDescription(ituneModule.getSubtitle());
                        }
                    } 
                }
                item.setId(syndEntry.getUri());
                item.setThumbnailUrl("");

                item.setTimeUploaded(syndEntry.getPublishedDate());
                item.setTitle(syndEntry.getTitle());

                videos.add(item);
            }
        }
        return videos;
    }

    public String fetchProviderVideo(String url) {
        throw new UnsupportedOperationException(this.getClass()
                + " does not need to fetch... it's rss so we just use the url in the feed");
    }

    public void providerCleanupAfterFetch(String url) {
        throw new UnsupportedOperationException(this.getClass()
                + " does not need to clean up... it's rss so we just use the url in the feed, and nothing is downloaded.");
    }

    protected SyndFeed fetchFeed(String rssUrl) {
        // this feed fetcher business knows how to handle gzipped feeds.. thank sweet baby jesus.
        LOG.info("fetching RSS feed: " + rssUrl);
        FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache);
        try {
            SyndFeed syndFeed = feedFetcher.retrieveFeed(new URL(rssUrl));
            LOG.info("done fetching RSS feed: " + rssUrl);
            return syndFeed;
        } catch (Exception e) {
            throw new RuntimeException("couldn't fetch feed: " + rssUrl, e);
        }
    }
}
